// Commonly used utility functions
//
// Copyright (C) Robert Bosch GmbH
// Date: Jan 2008
// Author: CR/RTC2-AP Kui Xu
#include "CommonUtil.h"
#include <sstream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>

using namespace std;

void removeSpace(const char *str, char *des_str) {
	int len = (int)strlen(str), i, j=0;
	for (i=0;i<len;i++) {
		if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') des_str[j++] = str[i];
	}
	des_str[j]='\0';
}

void removeSpace(string & str) {
	size_t found;
  
	found=str.find_first_of(SPACES);
	while (found!=string::npos)
	{
		str.erase(found, 1);
		found=str.find_first_of(SPACES,found);
	}
}

void removeSpaceFrom(const char *str, char *des_str, int from) {
	int len = (int)strlen(str), i, j=0;
	for (i=0;i<from;i++) des_str[j++] = str[i];
	for (i=from;i<len;i++) {
		if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') des_str[j++] = str[i];
	}
	des_str[j]='\0';
}

void trim(string & str) {
	// check for trivial case
	if (str.empty()) return;
	
	size_t found=str.find_first_not_of(SPACES);
	if (found==string::npos) {
		str.clear();
		return;
	}
	if (found>0) str.erase(0, found);

	found=str.find_last_not_of(SPACES);
	if (found<str.length()-1) str.erase(found+1);
}

void trimAll(vector<string> & list){
	vector<string>::iterator it;
	for ( it=list.begin() ; it < list.end(); it++ ) {
		trim(*it);
	}
}

bool startsWith(const string& str, const string& prefix)
{
	return (str.length() >= prefix.length()) &&
		equal(prefix.begin(), prefix.end(), str.begin());
}

bool endsWith(const string& str, const string& suffix)
{
	return (str.length() >= suffix.length()) &&
		equal(suffix.begin(), suffix.end(), str.end()-suffix.length());
}

void splitString(std::string *str, const char *spliter, std::vector<std::string> *result) {
	std::string tstr = *str;
	int i, slen = (int)strlen(spliter);
	result->clear();
	i = (int)tstr.find(spliter);
	while(i>=0) {
		result->push_back(tstr.substr(0,i));
		tstr = tstr.substr(i+slen, tstr.length()-i-slen);
		i = (int)tstr.find(spliter);
	}
	result->push_back(tstr);
}

void splitString(std::string *str, const char *spliter, std::vector<std::vector<std::string> > *result)
{
	std::string tstr = *str, tstr2, nametype;
	int i,j;
	std::vector<std::string> subresult, tresult;
	
	result->clear();
	i = (int)tstr.find(spliter[0]);
	while(i>=0) {
		tstr2 = tstr.substr(0,i);
		j = (int)tstr2.find(spliter[1]);
		if(j>=0) {
			subresult.push_back(tstr2.substr(0, j));
			tstr2 = tstr2.substr(j+1, tstr2.length()-j-1);
			splitString(&tstr2, spliter+2, &tresult);
			for(int k=0; k<(int)tresult.size(); k++)
				subresult.push_back(tresult[k]);
			result->push_back(subresult);
			subresult.clear();
		}
		tstr = tstr.substr(i+1, tstr.length()-i-1);
		i = (int)tstr.find(spliter);
	}
}

const wchar_t** splitString(std::string *str, const char *spliter, int &count)
{
	std::vector<std::string> tmpVec;
	const wchar_t ** result;
	splitString(str, spliter, &tmpVec);
	count = (int)tmpVec.size();
	result = new const wchar_t*[count];
	for(int i=0; i<count; i++) {
		wchar_t *tstr = new wchar_t[tmpVec[i].length()+1];
		mbstowcs(tstr, tmpVec[i].c_str(), tmpVec[i].length()+1);
		result[i] = tstr;
	}
	tmpVec.clear();
	return result;
}

/*
const wchar_t** splitString(wchar_t *str, const wchar_t *spliter, int &count)
{
	count = 0;
	if(!str || !spliter)
		return NULL;

	wchar_t *buffer, *token;

	buffer = new wchar_t[wcslen(str)+1], 
	wcsncpy(buffer, str, wcslen(str)+1);
	token = wcstok(buffer, spliter);
	while(token) {
		count++;
		token = wcstok(NULL, spliter);
	}
	if(count == 0)	return NULL;

	const wchar_t ** result = new const wchar_t*[count];
	int idx = 0;
	token = wcstok(str, spliter);
	while(token) {
		result[idx] = token;
		idx++;
		token = wcstok(NULL, spliter);
	}
	if(buffer)	delete []buffer;
	return result;
}
*/

const wchar_t** vectorToArray(std::vector<std::string> *vec)
{
	int num = (int)vec->size();
	const wchar_t ** outArray = new const wchar_t*[num];
	for(int i=0; i<num; i++) {
		wchar_t* tstr = new wchar_t[vec->at(i).length()+1];
		mbstowcs(tstr, vec->at(i).c_str(), vec->at(i).length()+1);
		outArray[i] = tstr;
	}
	return outArray;
}

/*
void splitString(const std::string &strSrc, 
				 const std::string &strSpliter, 
				 std::vector<std::string> &vecResult) 
{
	std::string tstr(strSrc);
	size_t nSpliterLen = strSpliter.size();
	vecResult.clear();
	size_t i = tstr.find(strSpliter);
	while(i != tstr.npos) 
	{
		vecResult.push_back(tstr.substr(0, i));
		tstr = tstr.substr(i + nSpliterLen, tstr.length() - i - nSpliterLen);
		i = tstr.find(strSpliter);
	}
	vecResult.push_back(tstr);
}
*/
void splitString(const string &strSrc, 
				 const string &strSpliter, 
				 vector<string> &vecResult,
				 unsigned int limit) 
{
	if (limit == (unsigned int)-1) {
		limit = (unsigned int)vecResult.max_size();
	}
	string tstr(strSrc);
	size_t nSpliterLen = strSpliter.size();
	vecResult.clear();
	
	size_t i = tstr.find(strSpliter);
	while(i != string::npos && vecResult.size() + 1 < limit) 
	{
		vecResult.push_back(tstr.substr(0, i));
		tstr.erase(0, i + nSpliterLen);
		i = tstr.find(strSpliter);
	}
	vecResult.push_back(tstr);
}

bool replaceParameter(std::string &strSentence, const std::string &strParam, const std::string &strValue)
{
	if (strSentence.empty() || strParam.empty() || strValue.empty())
		return false;

	std::vector<std::string> vecResult;
	splitString(strSentence, strParam, vecResult);

	size_t nVecSize = vecResult.size();
	strSentence.clear();
	for (size_t i = 0; i < nVecSize - 1; i++)
		strSentence += (vecResult[i] + strValue);

	strSentence += vecResult[nVecSize - 1];

	return true;
}

unsigned long str2Long(const char *str) {
	return (unsigned long)atol(str);
}

bool equalsIgnoreCase(std::string str1, std::string str2) 
{
	if (lowercase(str1).compare(lowercase(str2)) == 0)
		return true;
	return false;
}

std::string toStr(int val)
{
	char buf[1024];
	sprintf(buf, "%d", val);
	return buf;
}

std::string toStr(unsigned int val)
{
	char buf[1024];
	sprintf(buf, "%d", val);
	return buf;
}

std::string toStr(double val)
{
	char buf[1024];
	sprintf(buf, "%f", val);
	return buf;
}

std::string toStr(float val)
{
	char buf[1024];
	sprintf(buf, "%f", val);
	return buf;
}

std::string lowercase(std::string str) 
{
	const int length = str.length();
	for(int i=0; i<length ; i++)
	{
		str[i] = tolower(str[i]);
	}
	return str;
}

std::string uppercase(std::string str)
{
	const int length = str.length();
	for(int i=0; i<length ; i++)
	{
		str[i] = toupper(str[i]);
	}
	return str;
}

std::string replaceStr(std::string str, std::string subStr, std::string repStr)
{
	std::string result = str;
	size_t found = str.find(subStr);
	if (found != string::npos){
		result = str.replace(found, subStr.size(), repStr);
	}
	return result;
}

std::string replaceAll(std::string str, std::string subStr, std::string repStr)
{
	std::string result = str;
	size_t found = str.find(subStr);
	while (found != string::npos){
		result = result.replace(found, subStr.size(), repStr);
		found = result.find(subStr, found+repStr.size());
	}
	return result;
}

std::string joinString(std::vector<std::string> *str)
{
	std::string result;

	for(unsigned i=0; i<str->size()-1; i++) {
		result += (*str)[i] + " ";
	}
	if(str->size() >= 1) {
		result += (*str)[str->size()-1];
	}
	return result;
}

std::string joinString(std::vector<std::string> *str, int start, int end)
{
	std::string result("");

	if(start < 0 || end < 0 || start >= (int)str->size() || end >= (int)str->size() || start > end) {
		return result;
	}
	for(int i=start; i<end; i++) {
		result += (*str)[i] + " ";
	}
	result += (*str)[end];
	return result;
}

void getLocalIPAddress(std::vector<std::string> &ipAddrs)
{
#ifdef WIN32
	IP_ADAPTER_ADDRESSES* adapter_addresses(NULL);
	IP_ADAPTER_ADDRESSES* adapter(NULL);

	DWORD adapter_addresses_buffer_size = 8192;
	for (int attempts = 0; attempts != 3; ++attempts)
	{
		adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addresses_buffer_size);
		DWORD error = ::GetAdaptersAddresses(
			AF_UNSPEC, 
			GAA_FLAG_SKIP_ANYCAST | 
			GAA_FLAG_SKIP_MULTICAST | 
			GAA_FLAG_SKIP_DNS_SERVER |
			GAA_FLAG_SKIP_FRIENDLY_NAME, 
			NULL, 
			adapter_addresses,
			&adapter_addresses_buffer_size);
		
		if (ERROR_SUCCESS == error)
		{
			break;
		}
		else if (ERROR_BUFFER_OVERFLOW == error)
		{
			free(adapter_addresses);
			adapter_addresses = NULL;
			continue;
		}
		else
		{
			// Unexpected error code - log and throw
			free(adapter_addresses);
			adapter_addresses = NULL;
			return;
	    }
	}
	
	// Iterate through all of the adapters
	for (adapter = adapter_addresses; NULL != adapter; adapter = adapter->Next)
	{
		// Skip loopback adapters
		if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType)
			continue;
		
		// Parse all IPv4 and IPv6 addresses
		for (
			IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; 
			NULL != address;
			address = address->Next)
		{
			auto family = address->Address.lpSockaddr->sa_family;
			if (AF_INET == family)
			{
				// IPv4
				SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
				char str_buffer[INET_ADDRSTRLEN] = {0};
				inet_ntop(AF_INET, &(ipv4->sin_addr), str_buffer, INET_ADDRSTRLEN);
				ipAddrs.push_back(str_buffer);
			}
			else if (AF_INET6 == family)
			{
				// IPv6
				SOCKADDR_IN6* ipv6 = reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr);

				char str_buffer[INET6_ADDRSTRLEN] = {0};
				inet_ntop(AF_INET6, &(ipv6->sin6_addr), str_buffer, INET6_ADDRSTRLEN);

				std::string ipv6_str(str_buffer);

				// Detect and skip non-external addresses
				bool is_link_local(false);
				bool is_special_use(false);

				if (0 == ipv6_str.find("fe"))
				{
					char c = ipv6_str[2];
					if (c == '8' || c == '9' || c == 'a' || c == 'b')
					{
						is_link_local = true;
					}
				}
				else if (0 == ipv6_str.find("2001:0:"))
				{
					is_special_use = true;
				}

				if (! (is_link_local || is_special_use))
				{
					ipAddrs.push_back(ipv6_str);
				}
			}
			else
			{
				// Skip all other types of addresses
				continue;
			}
		}
	}

	free(adapter_addresses);
	adapter_addresses = NULL;
#endif
}

int getSubstrCount(std::string str, std::string subStr)
{
	std::string result = str;
	int count = 0, slen = subStr.length();
	int s, i = str.find(subStr);
	while(i >= 0) {
		count++;
		s = i+slen;
		i = str.find(subStr, s);
	}
	return count;
}
